/*
Copyright (C) 2011 Ing. Marek Hubal

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Other sources
paq9a archiver, Dec. 31, 2007 (C) 2007, Matt Mahoney

*/

#pragma once

#define INT8 char
#define INT16 short
#define INT32 int
#define INT64 __int64
#define UINT8 unsigned char
#define UINT16 unsigned short
#define UINT32 unsigned int
#define UINT64 unsigned __int64
#define CHAR char
#define PCHAR char*
#define CONST_PCHAR const char*
#define BYTE unsigned char
#define PBYTE unsigned char*
#define DOUBLE double
#define PVOID void*
#define CONST_PVOID const void*

#define ALIGN_32(AlVal) ((AlVal & (0x1f)) == 0 ? AlVal : (AlVal & (~0x1f)) + 32)
#define ALIGN_2048(AlVal) ((AlVal & (0x7ff)) == 0 ? AlVal : (AlVal & (~0x7ff)) + 2048)

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// IBitmap2
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#define BITMAP2_IMAGE_ERROR_OPEN_FILE -1
#define BITMAP2_IMAGE_ERROR_READ_FILE -2
#define BITMAP2_IMAGE_ERROR_FILE_HEADER_CORRUPTED -3
#define BITMAP2_IMAGE_ERROR_UNSUPORTED_BITS_PER_PIXEL -4
#define BITMAP2_IMAGE_ERROR_UNSUPORTED_COMPRESSION -5
#define BITMAP2_IMAGE_ERROR_CREATE_FILE -6
#define BITMAP2_IMAGE_ERROR_WRITE_FILE -7

#define COLORREF UINT32

// .....................................................................................................................
// Trieda IBitmap2
// .....................................................................................................................
class IBitmap2 {
public:
	INT32 Width, Height; // Rozmery
	COLORREF Pallete[2]; // Farby
	PBYTE RawData; // Data obrazku
public:
	INT32 RowSize; // Velkost jedneho riadku v bajtoch
	INT32 RawDataSize; // Velkost raw dat
	INT32 Count0, Count1; // Pocet nulovych a jednotkovych bitov
	INT32 ValidRowSize; // Platna dlzka riadku
	BYTE LastRowByteMask; // Mask posledneho platneho bajtu v riadku
	PBYTE *Rows; // Zaciatky riadkov
protected:
	bool __fastcall IncreaseXPosition(INT32 &X, INT32 &Y); // Zvysenie pozicie X
public:
	IBitmap2(void); // Konstruktor
	~IBitmap2(void); // Destruktor
public:
	void __fastcall Clear(void); // Uvolnenie objektu z pamate
public:
	bool __fastcall GetPixel(INT32 pX, INT32 pY); // Ziskanie hodnoty pixela na zadanej pozicii
	void __fastcall SetPixel(INT32 pX, INT32 pY, bool pValue); // Nastavenie hodnoty pixela na zadanej pozicii
	bool __fastcall FindNextForegroundPixel(INT32 &X, INT32 &Y); // Najdenie dalsieho vyskytu bodu popredia
public:
	INT32 __fastcall LoadFromBMP(CONST_PCHAR pFileName); // Nacitanie obsahu z BMP suboru
	INT32 __fastcall SaveToBMP(CONST_PCHAR pFileName); // Ulozenie obsahu do BMP suboru
	PBYTE __fastcall SaveToBMPBuffer(UINT32 &ResultLength); // Ulozenie obsahu do bufra vo formate BMP suboru
	IBitmap2* __fastcall Clone(void); // Vytvorenie kopie aktualneho obrazku
	void __fastcall Create(INT32 pWidth, INT32 pHeight); // Vytvorenie prazdneho obrazku
};
// .....................................................................................................................

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// IBitStream
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// .....................................................................................................................
// Trieda IBitStream
// .....................................................................................................................
class IBitStream {
protected:
	BYTE FCurrentMask; // Aktualna maska
	INT32 FCurrentIndex; // Aktualny index
public:
	PBYTE Data; // Data
	INT32 Capacity; // Aktualna kapacita a pocet bajtov
protected:
	void __fastcall Reallocate(void); // Realokacia pamate
	void __fastcall _AddBIT(bool pValue); // Zaradenie bitu
	bool __fastcall _GetBIT(void); // Nacitanie bitu
public:
	IBitStream(void); // Konstruktor
	~IBitStream(void); // Destruktor
public:
	void __fastcall Clear(void); // Uvolnenie objektu z pamate
	void __fastcall Rewind(void); // Pretocenie streamu na zaciatok
	void __fastcall AlignWriteToBYTE(bool pBit); // Zarovnanie zapisu na byte
	void __fastcall AlignReadToBYTE(void); // Zarovnanie citania na byte
	INT32 __fastcall GetCurrentLength(void); // Ziskanie aktualnej dlzky
	void __fastcall Allocate(INT32 pCapacity); // Alokacia internej pamate
public:
	void __fastcall AddBIT(bool pValue); // Zaradenie bitu
	void __fastcall AddBYTE(BYTE pValue); // Zaradenie UINT8
	void __fastcall AddWORD(UINT16 pValue); // Zaradenie UINT16
	void __fastcall AddDWORD(UINT32 pValue); // Zaradenie UINT32
	void __fastcall AddQWORD(UINT64 pValue); // Zaradenie UINT64
	void __fastcall AddBuffer(INT32 pLength, PBYTE pData); // Zaradenie bufra
	void __fastcall AddXBIT(INT32 pBitsCount, UINT64 pData); // Zaradenie X-bitoveho slova
public:
	bool __fastcall GetBIT(void); // Nacitanie bitu
	BYTE __fastcall GetBYTE(void); // Nacitanie UINT8
	UINT16 __fastcall GetWORD(void); // Nacitanie UINT16
	UINT32 __fastcall GetDWORD(void); // Nacitanie UINT32
	UINT64 __fastcall GetQWORD(void); // Nacitanie UINT64
public:
	INT32 __fastcall SaveToFile(CONST_PCHAR pFileName); // Ulozenie streamu do suboru
};
// .....................................................................................................................

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// IStopWatch
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#include <time.h>

// .....................................................................................................................
// Trieda IStopWatch
// .....................................................................................................................
class IStopWatch {
protected:
	clock_t FStart, FEnd; // Cas zaciatku a konca merania
	INT32 FRunCount; // Pocet iteracii v merani
public:
	IStopWatch(void); // Konstruktor
	~IStopWatch(void); // Destruktor
public:
	void __fastcall StartMeassure(void); // Spustenie merania
	void __fastcall EndMeassure(INT32 pRunCount); // Ukoncenie merania
public:
	INT32 __fastcall RunCount(void); // Pocet iteracii v merani
	DOUBLE __fastcall ElapsedTime(void); // Pocet uplynutych sekund v merani
	DOUBLE __fastcall Performance(void); // Vykonnost posledneho merania
public:
	void __fastcall PrintResultMessage(void); // Vypisanie vysledkov merania
};
// .....................................................................................................................

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// paq9a
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

typedef enum {COMPRESS, DECOMPRESS} Mode;

// .....................................................................................................................
// Trieda Squash
// .....................................................................................................................
class Squash {
protected:
	INT16 tab[4096];
public:
	Squash(); // Konstruktor
	INT32 __fastcall operator()(INT32 d);
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda Stretch
// .....................................................................................................................
class Stretch {
protected:
	INT16 t[4096];
public:
	Stretch(void); // Konstruktor
public:
	INT32 __fastcall operator()(INT32 p) const;
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda Ilog
// .....................................................................................................................
class Ilog {
protected:
	PBYTE t;
public:
  Ilog(void); // Konstruktor
  ~Ilog(void); // Destruktor
public:
  INT32 __fastcall operator()(UINT16 x) const {return t[x];}
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda StateMap
// .....................................................................................................................
class StateMap {
protected:
	const INT32 N;  // Number of contexts
	INT32 cxt;      // Context of last prediction
	UINT32 *t;       // cxt -> prediction in high 22 bits, count in low 10 bits
	static INT32 dt[1024];  // i -> 16K/(i+3)
public:
	StateMap(INT32 n=256); // Konstruktor
	~StateMap(void); // Destruktor
public:
	void __fastcall update(INT32 y, INT32 limit = 255);
	INT32 __fastcall p(INT32 cx);
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda Mix
// .....................................................................................................................
class Mix {
protected:
	const INT32 N;  // n
	INT32* wt;  // weights, scaled 24 bits
	INT32 x1, x2;    // inputs, scaled 8 bits (-2047 to 2047)
	INT32 cxt;  // last context (0..n-1)
	INT32 pr;   // last output
public:
	Mix(INT32 n=512); // Konstruktor
	~Mix(void); // Destruktor
public:
	INT32 __fastcall pp(INT32 p1, INT32 p2, INT32 cx);
	void __fastcall update(INT32 y);
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda APM
// .....................................................................................................................
class APM: public Mix {
public:
	APM(INT32 n); // Konstruktor
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda HashTable
// .....................................................................................................................
template <int B>
class HashTable {
protected:
	PBYTE t;  // table: 1 element = B bytes: checksum priority data data
	PBYTE t1;
	const UINT32 N;  // size in bytes
public:
	HashTable(INT32 n); // Konstruktor
	~HashTable(); // Destruktor
public:
	PBYTE __fastcall operator[](UINT32 i);
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda LZP
// .....................................................................................................................
class LZP {
private:
	const INT32 N, H; // buf, t sizes
	enum {MINLEN=24};  // minimum match length
	PBYTE buf;     // Rotating buffer of size N
	UINT32* t;      // hash table of pointers in high 24 bits, state in low 8 bits
	INT32 match;   // start of match
	INT32 len;     // length of match
	INT32 pos;     // position of next ch to write to buf
	UINT32 h;       // context hash
	UINT32 h1;      // hash of last 8 byte updates, shifting 4 bits to MSB
	UINT32 h2;      // last 4 updates, shifting 8 bits to MSB
	StateMap sm1; // len+offset -> p
	APM a1, a2, a3;   // p, context -> p
	INT32 literals, matches;  // statistics
public:
	UINT32 word0, word1;  // hashes of last 2 words (case insensitive a-z)
public:
	LZP(); // Konstruktor
	~LZP(); // Destruktor
public:
	virtual INT32 __fastcall c(void);     // predicted char
	virtual INT32 __fastcall c(INT32 i);// context
	INT32 __fastcall c4(void) {return h2;}  // order 4 context, c(1) in LSB
	INT32 __fastcall c8(void) {return h1;}  // hashed order 8 context
	virtual INT32 __fastcall p(void);     // probability that next char is c() * 4096
	virtual void __fastcall update(INT32 ch);  // update model with actual char ch
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda Predictor
// .....................................................................................................................
class Predictor {
protected:
	enum {N=11}; // number of contexts
	INT32 c0;      // last 0-7 bits with leading 1, 0 before LZP flag
	INT32 nibble;  // last 0-3 bits with leading 1 (1..15)
	INT32 bcount;  // number of bits in c0 (0..7)
	HashTable<16> t;  // context -> state
	StateMap sm[N];   // state -> prediction
	PBYTE cp[N];   // i -> state array of bit histories for i'th context
	PBYTE sp[N];   // i -> pointer to bit history for i'th context
	Mix m[N-1];  // combines 2 predictions given a context
	APM a1, a2, a3;  // adjusts a prediction given a context
	PBYTE t2;      // order 1 contexts -> state
	LZP *lzp;
public:
	Predictor(LZP *pObj); // Konstruktor
	~Predictor(void); // Destruktor
public:
	INT32 __fastcall p(void);
	void __fastcall update(INT32 y);
};
// .....................................................................................................................
// .....................................................................................................................
// Trieda Encoder
// .....................................................................................................................
class Encoder {
private:
	const Mode mode;       // Mod prace
	UINT32 x1, x2;            // Range, initially [0, 1), scaled by 2^32
	UINT32 x;                 // Decompress mode: last 4 input bytes of archive
	INT32 usize, csize;      // Buffered uncompressed and compressed sizes
	DOUBLE usum, csum;     // Total of usize, csize
	IBitStream *archive;
public:
	LZP* lzp;
	Predictor *predictor;
public:
	Encoder(Mode m, IBitStream* f, LZP *pLZP = NULL); // Konstruktor
	~Encoder(void); // Destruktor
public:
	void __fastcall Flush(void);  // call this when compression is finished
	INT32 __fastcall Code(INT32 y = 0);
	void __fastcall Count(void);
};
// .....................................................................................................................


INT32 __fastcall CompressBitStream(IBitStream *pSource, IBitStream *Result, LZP *pLZP = NULL);
INT32 __fastcall DecompressBitStream(IBitStream *pSource, INT32 pSourceLength, IBitStream *Result, LZP *pLZP = NULL);

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// cbi stream
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

typedef struct {
	INT32 CompressionMode;
	INT32 PageIndex;
	PCHAR FileName;
} CBI_PARAMS, *PCBI_PARAMS;

#pragma pack(1)
typedef struct {
	__int64 DCREATE;
	unsigned int PAGES_COUNT;
	unsigned int COMPRESSION;
	unsigned int MAX_WIDTH;
	unsigned int MAX_HEIGHT;
	unsigned __int64 ORIGINAL_SIZE;
	unsigned __int64 COMPRESSED_SIZE;
} CBI_STREAM_INFO, *PCBI_STREAM_INFO;
typedef struct {
	unsigned int WIDTH;
	unsigned int HEIGHT;
	unsigned int DPI_X;
	unsigned int DPI_Y;
	unsigned int COLOR_BACK, COLOR_FORE;
	unsigned __int64 COMPRESSED_SIZE;
	unsigned __int64 ORIGINAL_SIZE;
} CBI_PAGE_INFO, *PCBI_PAGE_INFO;
#pragma pack()

#define CBI_ERROR_CREATE_FILE -1-100
#define CBI_ERROR_WRITE_FILE -2-100
#define CBI_ERROR_OPEN_FILE -3-100
#define CBI_ERROR_READ_FILE -4-100
#define CBI_ERROR_INVALID_STRUCTURE -5-100
#define CBI_ERROR_PAGE_OUT_OF_RANGE -6-100
#define CBI_ERROR_UNSUPPORTED_COMPRESSION -7-100

#pragma pack(1)
typedef struct {
	BYTE SIGNATURE[4];
} CBI_FILE_HEADER, *PCBI_FILE_HEADER;
typedef struct {
	UINT64 DCREATE;
	UINT32 PAGES_COUNT;
	UINT32 COMPRESSION;
	UINT32 WIDTH;
	UINT32 HEIGHT;
	UINT64 ORIGINAL_SIZE;
	UINT64 COMPRESSED_SIZE;
} CBI_STREAM_HEADER, *PCBI_STREAM_HEADER;
typedef struct {
	UINT64 PAGE_NUM;
	UINT32 WIDTH;
	UINT32 HEIGHT;
	UINT32 DPI_X;
	UINT32 DPI_Y;
	COLORREF COLOR_BACK, COLOR_FORE;
	UINT64 DATA_OFFSET;
	UINT64 DATA_SIZE;
	UINT64 ORIGINAL_SIZE;
} CBI_PAGE_HEADER, *PCBI_PAGE_HEADER;
#pragma pack()

// .....................................................................................................................
// Trieda IList
// .....................................................................................................................
class IList {
public:
	PVOID* Items; // Zaznamy
	INT32 Count, Capacity; // Pocet a kapacita
public:
	IList(void); // Konstruktor
	~IList(void); // Destruktor
public:
	void __fastcall Clear(void); // Uvolnenie zoznamu z pamate
	INT32 __fastcall Add(PVOID pValue); // Zaradenie hodnoty
	void __fastcall Reallocate(INT32 pCapacity, bool pCopy); // Realokacia pamate podla potreby
};
// .....................................................................................................................

// .....................................................................................................................
// Trieda ICBIStream
// .....................................................................................................................
class ICBIStream {
protected:
	PVOID FFile; // Subor streamu
	INT32 FCompressionMode;
	CHAR FFileName[1024];
	bool FReadMode;
public:
	IList Pages; // Zoznam stranok
protected:
	virtual void __fastcall ClearPages(void); // Uvolnenie stranok
public:
	ICBIStream(void); // Konstruktor
	virtual ~ICBIStream(void); // Destruktor
public:
	virtual INT32 __fastcall Create(CONST_PCHAR pFileName); // Vytvorenie streamu
	virtual INT32 __fastcall Close(void); // Uzatvorenie streamu
	virtual INT32 __fastcall AddPage(IBitmap2 *pImage); // Zaradenie stranky
	virtual INT32 __fastcall Open(CONST_PCHAR pFileName); // Otvorenie streamu
	virtual INT32 __fastcall GetPageImage(INT32 pIndex, IBitmap2 *Result); // Ziskanie stranky ako obrazku
public:
	static ICBIStream* __fastcall CreateCBIStream(INT32 pCompressionMode); // Vytvorenie objektu streamu podla typu kompresie
	static ICBIStream* __fastcall OpenCBIStream(CONST_PCHAR pFileName, INT32 &ErrorCode); // Vytvorenie prislusneho objektu a otvorenie streamu
	static INT32 __fastcall ReadStreamInfo(CONST_PCHAR pFileName, PCBI_STREAM_INFO Result); // Nacitanie informacii o streame
	static INT32 __fastcall ReadPagesInfo(CONST_PCHAR pFileName, PCBI_PAGE_INFO Result); // Nacitanie info o strankach v cbi streame
};
// .....................................................................................................................

// .....................................................................................................................
// Trieda ICBIStream0
// .....................................................................................................................
class ICBIStream0 : public ICBIStream {
public:
	ICBIStream0(void); // Konstruktor
	virtual ~ICBIStream0(void); // Destruktor
public:
	virtual INT32 __fastcall Create(CONST_PCHAR pFileName); // Vytvorenie streamu
	virtual INT32 __fastcall Close(void); // Uzatvorenie streamu
	virtual INT32 __fastcall AddPage(IBitmap2 *pImage); // Zaradenie stranky
	virtual INT32 __fastcall Open(CONST_PCHAR pFileName); // Otvorenie streamu
	virtual INT32 __fastcall GetPageImage(INT32 pIndex, IBitmap2 *Result); // Ziskanie stranky ako obrazku
};
// .....................................................................................................................

#define MAX_AREA_WIDTH 64
#define MAX_AREA_WIDTH_B 8
#define MAX_AREA_HEIGHT 64
#define DATA_AREA_LENGTH MAX_AREA_HEIGHT * MAX_AREA_WIDTH_B
#define MAX_AREA_WIDTH_BITS 6
#define MAX_AREA_HEIGHT_BITS 6

typedef struct {
	INT32 X, Y; // Pozicia
	INT32 W, H; // Rozmery
	INT32 AbsPos; // Absolutna pozicia
	INT32 First, Count; // Zaciatok rovnakych a pocet
	BYTE RawData[DATA_AREA_LENGTH]; // Raw data
} AREA, *PAREA;

typedef struct {
	IBitmap2 *Image;
	INT32 MinX, MinY, MaxX, MaxY;
	INT32 X, Y;
	INT32 Width, Height;
	INT32 MaskStartX, MaskStartY;
	BYTE UsedMask[2 * MAX_AREA_WIDTH * MAX_AREA_HEIGHT];
} SEARCH_AREA, *PSEARCH_AREA;

// .....................................................................................................................
// Trieda ICBIStream1
// .....................................................................................................................
class ICBIStream1 : public ICBIStream {
public:
	ICBIStream1(void); // Konstruktor
	virtual ~ICBIStream1(void); // Destruktor
public:
	virtual INT32 __fastcall Create(CONST_PCHAR pFileName); // Vytvorenie streamu
	virtual INT32 __fastcall Close(void); // Uzatvorenie streamu
	virtual INT32 __fastcall AddPage(IBitmap2 *pImage); // Zaradenie stranky
	virtual INT32 __fastcall Open(CONST_PCHAR pFileName); // Otvorenie streamu
	virtual INT32 __fastcall GetPageImage(INT32 pIndex, IBitmap2 *Result); // Ziskanie stranky ako obrazku
public:
	static void __fastcall SetPixel(PAREA pArea, INT32 pX, INT32 pY);
	static bool __fastcall GetPixel(PAREA pArea, INT32 pX, INT32 pY);
	static INT32 __fastcall CompareAREA(PAREA P1, PAREA P2);
	static void __fastcall DrawArea(IBitmap2 *pImage, PAREA pArea, INT32 pX, INT32 pY);
	static void __fastcall InitStructure(INT32 pX, INT32 pY, PSEARCH_AREA pValue);
	static void __fastcall InspectArea(PSEARCH_AREA pArea);
	static void __fastcall CreateAreaFromSearchStruct(IBitmap2 *pImage, PSEARCH_AREA pSearchArea, PAREA Result);
	static void __fastcall SaveAREAData(IBitStream *pStream, PAREA pArea, INT32 pCol);
	static void __fastcall ReadAREAData(IBitStream *pStream, PAREA pArea, INT32 pCol);
};
// .....................................................................................................................


#define MAX_AREA2_WIDTH 64
#define MAX_AREA2_WIDTH_B 8
#define MAX_AREA2_HEIGHT 128
#define DATA_AREA2_LENGTH MAX_AREA2_HEIGHT * MAX_AREA2_WIDTH_B
#define MAX_AREA2_WIDTH_BITS 6
#define MAX_AREA2_HEIGHT_BITS 7

#pragma pack(16)
typedef struct {
	INT32 X, Y; // Pozicia
	INT32 W, H; // Rozmery
	INT32 AbsPos; // Absolutna pozicia
	INT32 First, Count; // Zaciatok rovnakych a pocet
	INT32 NormalIndex, BaseIndex, BaseIndex2;
	INT32 BaseItemCount;
	INT32 Count1;
	BYTE RawData[DATA_AREA2_LENGTH]; // Raw data
} AREA2, *PAREA2;

typedef struct {
	INT32 X, Y; // Pozicia
	INT32 AbsPos; // Absolutna pozicia
	INT32 BaseIndex;
} MINIAREA2, *PMINIAREA2;

typedef struct {
	IBitmap2 *Image;
	INT32 MinX, MinY, MaxX, MaxY;
	INT32 X, Y;
	INT32 Width, Height;
	INT32 MaskStartX, MaskStartY;
	BYTE UsedMask[2 * MAX_AREA2_WIDTH * MAX_AREA2_HEIGHT];
} SEARCH_AREA2, *PSEARCH_AREA2;
#pragma pack()

// .....................................................................................................................
// Trieda ICBIStream2
// .....................................................................................................................
class ICBIStream2 : public ICBIStream {
public:
	ICBIStream2(void); // Konstruktor
	virtual ~ICBIStream2(void); // Destruktor
public:
	virtual INT32 __fastcall Create(CONST_PCHAR pFileName); // Vytvorenie streamu
	virtual INT32 __fastcall Close(void); // Uzatvorenie streamu
	virtual INT32 __fastcall AddPage(IBitmap2 *pImage); // Zaradenie stranky
	virtual INT32 __fastcall Open(CONST_PCHAR pFileName); // Otvorenie streamu
	virtual INT32 __fastcall GetPageImage(INT32 pIndex, IBitmap2 *Result); // Ziskanie stranky ako obrazku
public:
	static void __fastcall SetPixel(PAREA2 pArea, INT32 pX, INT32 pY);
	static bool __fastcall GetPixel(PAREA2 pArea, INT32 pX, INT32 pY);
	static INT32 __fastcall CompareAREA(PAREA2 P1, PAREA2 P2);
	static void __fastcall DrawArea(IBitmap2 *pImage, PAREA2 pArea, INT32 pX, INT32 pY);
	static void __fastcall InitStructure(INT32 pX, INT32 pY, PSEARCH_AREA2 pValue);
	static void __fastcall InspectArea(PSEARCH_AREA2 pArea);
	static void __fastcall CreateAreaFromSearchStruct(IBitmap2 *pImage, PSEARCH_AREA2 pSearchArea, PAREA2 Result);
	static void __fastcall SaveAREAData(IBitStream *pStream, PAREA2 pArea);
	static void __fastcall SaveAREAData(IBitStream *pStream, PAREA2 pArea, INT32 pCol);
};
// .....................................................................................................................

// .....................................................................................................................
// Trieda ICBIStream3
// .....................................................................................................................
class ICBIStream3 : public ICBIStream {
protected:
	IList FAreas;
	PMINIAREA2 AreasData;
	PAREA2 BaseAreasData;
	INT32 AreasCount, BaseCount;
public:
	ICBIStream3(void); // Konstruktor
	virtual ~ICBIStream3(void); // Destruktor
public:
	virtual INT32 __fastcall Create(CONST_PCHAR pFileName); // Vytvorenie streamu
	virtual INT32 __fastcall Close(void); // Uzatvorenie streamu
	virtual INT32 __fastcall AddPage(IBitmap2 *pImage); // Zaradenie stranky
	virtual INT32 __fastcall Open(CONST_PCHAR pFileName); // Otvorenie streamu
	virtual INT32 __fastcall GetPageImage(INT32 pIndex, IBitmap2 *Result); // Ziskanie stranky ako obrazku
};
// .....................................................................................................................
